package core

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"time"
)

type WorkConfig struct {
	WorkList []string `json:"work_list"`
	Author   string   `json:"author"`
	Project  string   `json:"project"`
	Token    string   `json:"token"`
}

var GlobalStates = "NotOK"

func load_config() *WorkConfig {
	// 打开JSON配置文件
	file, err := os.Open("config.json")
	if err != nil {
		fmt.Printf("Error opening config file: %v\n", err)
		return nil
	}
	defer file.Close()

	// 读取文件内容
	byteValue, err := io.ReadAll(file)
	if err != nil {
		fmt.Printf("Error reading config file: %v\n", err)
		return nil
	}

	// 定义一个WorkConfig实例
	var config WorkConfig

	// 将JSON数据解析到结构体
	err = json.Unmarshal(byteValue, &config)
	if err != nil {
		fmt.Printf("Error unmarshalling JSON: %v\n", err)
		return nil
	}

	fmt.Printf("config: %v\n", config)
	return &config
}

func hf_download(site string, author string, project string, fileName string, token string) {
	// url := fmt.Sprintf("https://huggingface.co/%v/%v/resolve/main/%v?download=true", author, project, fileName)
	// url := fmt.Sprintf("https://hf-mirror.com/%v/%v/resolve/main/%v?download=true", author, project, fileName)
	url := fmt.Sprintf("https://%v/%v/%v/resolve/main/%v?download=true", site, author, project, fileName)

	file_path := filepath.Join("out_lmsys", fileName)

	// 创建请求
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		fmt.Printf("Error creating request: %v\n", err)
		return
	}

	// 设置Authorization头
	if len(token) > 0 {
		req.Header.Set("Authorization", "Bearer "+token)
	}

	// 检查是否文件已经存在
	var offset int64 = 0
	if fileInfo, err := os.Stat(file_path); err == nil {
		offset = fileInfo.Size()
	}

	// 设置断点续传的Range头
	if offset > 0 {
		req.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset))
	}

	// 发送请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Printf("Error making request: %v\n", err)
		return
	}
	defer resp.Body.Close()

	// 检查响应码
	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusPartialContent {
		if resp.Status == "416 Requested Range Not Satisfiable" {
			fmt.Println("Download is Completed!")
			GlobalStates = "AllOK"
		} else {
			fmt.Printf("Failed to download file: %s\n", resp.Status)
		}
		return
	}

	// 打开文件
	file, err := os.OpenFile(file_path, os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		fmt.Printf("Error opening file: %v\n", err)
		return
	}
	defer file.Close()

	// 如果有偏移量，移动到文件末尾
	if offset > 0 {
		file.Seek(offset, io.SeekStart)
	}

	// 创建一个较大的缓冲区
	buf := make([]byte, 32*1024*1024) // 32 MB

	curOffset := offset
	fmt.Printf("curOffset: %v\n", curOffset)

	fmt.Printf("resp.Header: %v\n", resp.Header)
	fmt.Printf("resp.length: %v\n", resp.ContentLength)

	last_process := 0.0
	curProcess := float64(curOffset) / float64(resp.ContentLength) * 100.0
	fmt.Printf("curProcess: %v%%\n", curProcess)

	// 写入文件
	for {
		n, err := resp.Body.Read(buf)
		if n > 0 {
			if _, err := file.Write(buf[:n]); err != nil {
				fmt.Printf("Error writing to file: %v\n", err)
				return
			}
			curOffset = curOffset + int64(n)
			curProcess = float64(curOffset) / float64(resp.ContentLength) * 100.0
			delta := curProcess - last_process
			if delta >= 5.00 {
				last_process = curProcess
				fmt.Printf("time.Now(): %v\n", time.Now())
				fmt.Printf("curProcess: %v%%\n", curProcess)
			}
		}
		if err == io.EOF {
			break
		}
		if err != nil {
			fmt.Printf("Error reading response body: %v\n", err)
			return
		}
	}

	fmt.Println("Download completed successfully")
}

func HfDownload() {
	config := load_config()
	work_list := config.WorkList
	lenth := len(work_list)
	for i := 0; i < lenth; i++ {
		filename := work_list[i]
		fmt.Printf("\n\n[file] %v\n", filename)
		GlobalStates = "NotOK"
		for i := 0; i < 5; i++ {
			hf_download("hf-mirror.com", config.Author, config.Project, filename, config.Token)
			if GlobalStates == "AllOK" {
				break
			}
			time.Sleep(time.Second * 10)
			// hf_download("huggingface.co", config.Author, config.Project, filename, config.Token)
			// if GlobalStates == "AllOK" {
			// 	break
			// }
		}
	}
}
